Skip to content

refactor(backend): extract admin CRUD into internal/admin package#16

Merged
revtex merged 1 commit intodevfrom
restructure/phase-2-admin-package
Apr 24, 2026
Merged

refactor(backend): extract admin CRUD into internal/admin package#16
revtex merged 1 commit intodevfrom
restructure/phase-2-admin-package

Conversation

@revtex
Copy link
Copy Markdown
Owner

@revtex revtex commented Apr 24, 2026

What

The WebSocket layer is now protocol-only; admin CRUD, config, import, export, and radioreference business logic live in a new transport-agnostic internal/admin package.

  • New internal/admin/ package (62 Operations methods across 18 files: users.go, systems.go, talkgroups.go, tags.go, groups.go, units.go, api_keys.go, dirmonitors.go, downstreams.go, webhooks.go, shared_links.go, settings.go, transcription.go, radioreference.go, filesystem.go, imports.go, exports.go, operations.go). No imports of internal/ws or net/http.
  • internal/admin/operations.go defines an EventSink interface (BroadcastAdminEvent, BroadcastCFG, DisconnectByUser, ClientCount). ws.Hub implements it; admin.New takes it at construction.
  • internal/ws/admin_router.go replaces admin_ops.go as the thin transport adapter. The adminOpHandlers map preserves every wire op (users.list, systems.create, config.update, export.config, etc.) byte-identically.
  • Live-state ops (activity.stats, activity.chart, activity.top-talkgroups, logs.query, logs.level) stay on *Client — they read hub in-memory state that the admin package doesn't have.
  • internal/ws/admin_ops.go deleted (3,201 lines).
  • ws.HubDeps is now a type alias for admin.Deps. Hub construction signature at the call site is unchanged: ws.NewHub(queries, version, ws.HubDeps{...}) still works.
  • main.go updated: SensitiveSettingKeys moved from ws to admin.

Tests

admin_ops_settings_test.go was split:

  • CRUD semantics → internal/admin/settings_test.go
  • Dispatch / error envelope → internal/ws/admin_router_test.go (new)

Wire-protocol guarantee

Every ADM_REQ / ADM_RES frame, action name, error envelope, and payload key is byte-identical to pre-PR. The frontend sees no change. There is an explicit test in admin_router_test.go that enumerates the expected wire ops and asserts the router exposes exactly that set (no additions, no missing).

Blast radius

  • No route changes
  • No schema changes
  • No auth surface changes
  • No wire-protocol changes
  • internal/admin is a net-new package with no external consumers outside internal/ws and cmd/server

Diff

Net +428 LOC (3,724 added, 3,296 removed — mostly a move out of the 3,201-line admin_ops.go).

Verification

  • go build ./... && go vet ./... — green
  • go test ./internal/ws/... ./internal/admin/... ./internal/api/... — all three packages pass
  • go test ./... — full suite green

Changelog

[Unreleased] bullet added under ### Changed.

Phase 2 of the directory restructure. The WebSocket layer is now
protocol-only; admin CRUD / config / import-export business logic
lives in a new transport-agnostic internal/admin package.

Changes:

- New internal/admin/ package with Operations struct. Files split by
  feature: users.go, systems.go, talkgroups.go, tags.go, groups.go,
  units.go, api_keys.go, dirmonitors.go, downstreams.go, webhooks.go,
  shared_links.go, settings.go, transcription.go, radioreference.go,
  filesystem.go, imports.go, exports.go. Does not import internal/ws
  or net/http.
- internal/admin/operations.go defines the EventSink interface
  (BroadcastAdminEvent, BroadcastCFG, DisconnectByUser, ClientCount).
  ws.Hub implements it; Operations.New takes it at construction.
- internal/ws/admin_router.go replaces admin_ops.go as the transport
  adapter. The adminOpHandlers map preserves every wire-protocol op
  name (users.list, systems.create, config.update, export.config,
  etc.) byte-identically. Live-state ops (activity.stats,
  activity.chart, logs.query, logs.level, activity.top-talkgroups)
  stay on *Client because they read hub in-memory state.
- internal/ws/admin_ops.go deleted (3,201 lines removed).
- Hub construction unchanged at the call site: NewHub(queries,
  version, HubDeps{...}) still works. HubDeps is now a type alias
  for admin.Deps.
- cmd/server/main.go updated: SensitiveSettingKeys moved from ws to
  admin package.
- Tests: admin_ops_settings_test.go split into
  internal/admin/settings_test.go (CRUD semantics) and
  internal/ws/admin_router_test.go (dispatch + error envelope).

No wire-protocol, auth, or route changes. All frames, error
envelopes, and action names are byte-identical to before.
@revtex revtex merged commit 3a8e4c8 into dev Apr 24, 2026
4 checks passed
@revtex revtex deleted the restructure/phase-2-admin-package branch April 24, 2026 19:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant